#include <buola/scene.h>
#include <buola/scene/csceneview.h>
#include <buola/scene/ccamera.h>
#include <buola/scene/cperspectivecamera.h>
#include <buola/scene/cscene.h>
#include <buola/scene/geodes/ccube.h>
#include <buola/scene/geodes/csphere.h>
#include <buola/scene/geodes/cplane.h>
#include <buola/scene/geodes/ccylinder.h>
#include <buola/scene/geodes/ccapsule.h>
#include <buola/scene/transform/crttransform.h>
#include <buola/scene/transform/crigidbody.h>
#include <buola/scene/cimagerenderer.h>
#include <buola/scene/controllers/ccameracontroller.h>
#include <buola/scene/controllers/cphysicscontroller.h>
#include <buola/image/io.h>
#include <buola/image/cgc.h>
#include <buola/gui/ctoolkit.h>
#include <buola/app/capp.h>

using namespace buola;

int main(int pNArg,char **pArgs)
{
    buola_init(pNArg,pArgs);

    try
    {
        CApp lApp;

        gui::get_toolkit()->GetOpenGLGC()->MakeCurrent(); ///\todo remove this ugly hack!
        
        //create the scene
        scene::PScene lScene=new scene::CScene;
        scene::PRigidBody lSphere1=new scene::CRigidBody(new scene::CSphere,1,mat::translation_3d({0,0,3}));
        lScene->World()->AddChild(lSphere1);
        scene::PRigidBody lPlane=new scene::CRigidBody(new scene::CPlane,0,mat::identity_3d());
        lScene->World()->AddChild(lPlane);
        scene::PRigidBody lSphere2=new scene::CRigidBody(new scene::CSphere,1,mat::translation_3d({0,1,1}));
        lScene->World()->AddChild(lSphere2);
        scene::PRigidBody lSphere3=new scene::CRigidBody(new scene::CSphere,1,mat::translation_3d({0,0,6}));
        lScene->World()->AddChild(lSphere3);
        scene::PRigidBody lSphere4=new scene::CRigidBody(new scene::CSphere,1,mat::translation_3d({0,0,10}));
        lScene->World()->AddChild(lSphere4);
        scene::PRigidBody lSphere5=new scene::CRigidBody(new scene::CCapsule(2,0.7),1,mat::translation_3d({0,0,15}));
        lScene->World()->AddChild(lSphere5);
        scene::PRigidBody lSphere6=new scene::CRigidBody(new scene::CCube(1.0,1.3,1.7),1,mat::translation_3d({0,0,21}));
        lScene->World()->AddChild(lSphere6);
        scene::PRigidBody lSphere7=new scene::CRigidBody(new scene::CCylinder(2.0,0.5,30,true),1,mat::translation_3d({0.2,0.2,29}));
        lScene->World()->AddChild(lSphere7);

        lScene->AddBody(lPlane);
        lScene->AddBody(lSphere1);
        lScene->AddBody(lSphere2);
        lScene->AddBody(lSphere3);
        lScene->AddBody(lSphere4);
        lScene->AddBody(lSphere5);
        lScene->AddBody(lSphere6);
        lScene->AddBody(lSphere7);
        
        scene::PPerspectiveCamera lCamera=new scene::CPerspectiveCamera;
        lCamera->LookAt({0,0,2},{25,0,2},{0,0,1});

        scene::CImageRenderer lRenderer;
        lRenderer.SetCamera(lCamera);
        lRenderer.AddScene(lScene);

        img::CImage_rgb8 lImage({640,640});
        
        lRenderer.GetImage(lImage);

        img::save(lImage,io::file("scene.ppm"));
        
        scene::PSceneView lView=new scene::CSceneView;
        lView->SetCamera(lCamera);
        lView->AddScene(lScene);
        lView->AddController(new scene::CCameraController(lCamera));
        lView->AddController(new scene::CPhysicsController(lScene));
        lView->Map(CSize_d(800,600));
        
        lApp.Run();
    }
    catch(std::exception &pE)
    {
        msg_info() << pE.what() << "\n";
    }

    return buola_finish();
}